// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

// Get the function name, file name, and line number for a PC value.
// We use the DWARF debug information to get this.  Rather than write
// a whole new library in C, we use the existing Go library.
// Unfortunately, the Go library is only available if the debug/elf
// package is imported (we use debug/elf for both ELF and Mach-O, in
// this case).  We arrange for the debug/elf package to register
// itself, and tweak the various packages that need this information
// to import debug/elf where possible.



// Return function/file/line information for PC.
func getPCInfo(pc uintptr, function *string, file *string, line *int) bool

// Return the value of a symbol.
func getSymbolValue(sym string, val *uintptr) bool

// A gccgo specific hook to use debug info to get file/line info.
// This is called by debug/elf to register the function that returns function/file/line information.
func RegisterDebugLookup(ifn func(pc uintptr, function *string, file *string, line *int) bool,
	sfn func(sym string, val *uintptr) bool)

// Caller reports file and line number information about function invocations on
// the calling goroutine's stack.  The argument skip is the number of stack frames
// to ascend, with 0 identifying the caller of Caller.  (For historical reasons the
// meaning of skip differs between Caller and Callers.) The return values report the
// program counter, file name, and line number within the file of the corresponding
// call.  The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
	var fn string
	pcs := make([]uintptr, 1)

	if n := Callers(skip + 1, pcs); n >= 1 {
		pc = pcs[0]
		ok = getPCInfo(pc, &fn, &file, &line)
	}

	return
}

type Func struct {
	name  string
	entry uintptr // entry pc
}

// FuncForPC returns a *Func describing the function that contains the
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func {
	var fn, file string
	var line int
	var val uintptr

	if !getPCInfo(pc, &fn, &file, &line) {
		return nil
	}
	if !getSymbolValue(fn, &val) {
		return nil
	}

	return &Func{fn, val}
}

// Name returns the name of the function.
func (f *Func) Name() string {
	return f.name
}

// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr {
	return f.entry
}

// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
	var fn string

	getPCInfo(pc, &fn, &file, &line)
	return
}
